Skip to content

Conversation

@panteliselef
Copy link
Member

@panteliselef panteliselef commented Oct 29, 2025

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Checkout now shows "total due after free trial" where applicable.
  • Improvements

    • Updated supported API compatibility version.
    • Billing and pricing UI more robustly handles absent/nullable annual pricing and toggles.
    • Payment method labels and checkout summaries display gracefully when details are incomplete.
    • Checkout payload now uses a payment method identifier.
    • Billing data parsing now tolerates missing fields to keep the UI stable.
  • Bug Fixes

    • Prevented errors when optional billing fields are absent or null.
  • Tests

    • Expanded checkout/pricing tests and helpers to validate line items and totals.

@changeset-bot
Copy link

changeset-bot bot commented Oct 29, 2025

🦋 Changeset detected

Latest commit: 1d1b602

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@clerk/clerk-js Patch
@clerk/backend Patch
@clerk/chrome-extension Patch
@clerk/clerk-expo Patch
@clerk/agent-toolkit Patch
@clerk/astro Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/remix Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Oct 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
clerk-js-sandbox Ready Ready Preview Comment Nov 10, 2025 6:18pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 29, 2025

Walkthrough

This PR updates API version constants to '2025-11-10', broadens many billing-related types and JSON shapes to be optional/null, adjusts backend resource mappers and frontend resource classes to handle nullable fields, switches UI checks from numeric amount tests to presence checks, renames a checkout param (paymentSourceId → paymentMethodId), and updates tests and a changeset.

Changes

Cohort / File(s) Summary
API Version Constants
packages/backend/src/constants.ts, packages/clerk-js/src/core/constants.ts
Updated exported API version constants from '2025-04-10' to '2025-11-10'.
Changeset & Handshake Test
.changeset/hot-jars-smell.md, packages/backend/src/tokens/__tests__/handshake.test.ts
Added changeset for patch releases (references 2025-10-01); updated handshake test expectation for __clerk_api_version to '2025-10-01'.
Shared Types & JSON Schemas
packages/shared/src/types/billing.ts, packages/shared/src/types/json.ts, packages/shared/src/types/commerceSettings.ts
Broadened many types to be optional/null (plans, fees, features, payment methods, payers, checkout totals); added totalDueAfterFreeTrial/proration; renamed paymentSourceIdpaymentMethodId; added optional expiry/timestamps and nullable stripe key.
Backend Resource Mappers & JSON
packages/backend/src/api/resources/CommercePlan.ts, packages/backend/src/api/resources/Feature.ts, packages/backend/src/api/resources/CommerceSubscription*.ts, packages/backend/src/api/resources/CommerceSubscriptionItem.ts, packages/backend/src/api/resources/JSON.ts
Converted fields to nullable/optional, removed productId, adopted camelCase public fields, updated fromJSON mappings to coalesce missing values and handle nullable monetary fields.
Frontend Core Resources
packages/clerk-js/src/core/resources/*.ts (BillingPlan, BillingPayer, BillingPaymentMethod, BillingPayment, BillingSubscription, BillingCheckout, Feature, CommerceSettings)
Made many public fields optional/null; introduced protected fromJSON helpers and unix-epoch→Date conversions; adjusted CommerceSettings stripe key default to null; changed free-trial handling and other nullable mappings.
UI Components (billing & pricing)
packages/clerk-js/src/ui/components/* (CheckoutForm.tsx, CheckoutComplete.tsx, PaymentAttemptPage.tsx, PlanDetails.tsx, PricingTable*.tsx, SubscriptionDetails, SubscriptionsList.tsx, PaymentMethods/PaymentMethodRow.tsx)
Replaced numeric .amount > 0 checks with presence checks (Boolean(annualMonthlyFee)); added null-guards and some non-null assertions; defensive rendering for missing paymentType/cardType; minor formatting/TODO removal.
Billing Logic & Utilities
packages/clerk-js/src/utils/billing.ts, packages/clerk-js/src/ui/contexts/components/Plans.tsx, packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts, packages/clerk-js/src/core/modules/billing/namespace.ts
Reordered and made totals mapping truthy-aware (totalDueNow, credit, pastDue, totalDueAfterFreeTrial); switched eligibility/plan-switch checks to Boolean(annualMonthlyFee); allowed orgId param to be `string
Subscription Items / Backend typings
packages/backend/src/api/resources/CommerceSubscriptionItem.ts
Converted several nullable fields to optional/undefined semantics (nextPayment now possibly undefined, amount made optional, payerId optional, lifetimePaid optional) and normalized fromJSON mappings.
Tests & Integration
packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx, packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx, integration/tests/pricing-table.test.ts, packages/shared/src/react/__tests__/commerce.test.tsx
Updated fixtures to use null for annual fees and adjusted payer/test shape; added test helpers (matchLineItem, countLineItems) and extended assertions for checkout line items.
Hooks / Checkout Types
packages/shared/src/react/hooks/useCheckout.ts
Added planPeriodStart property to CheckoutProperties null-state shape.
Bundlewatch Config
packages/clerk-js/bundlewatch.config.json
Slightly increased maxSize for ./dist/checkout*.js from 8.8KB → 8.82KB.

Sequence Diagram(s)

sequenceDiagram
  participant UI as Billing UI
  participant Checkout as Checkout Flow
  participant Mapper as JSON → Resource Mapper
  participant API as Billing Service

  Note over UI,Checkout: User views plans / opens checkout
  UI->>Checkout: request checkout/plan data
  Checkout->>API: fetch JSON payload
  API-->>Mapper: returns JSON (nullable/optional fields)
  Mapper->>Mapper: normalize nullable fields, convert epochs → Date
  Mapper-->>Checkout: BillingCheckoutResource / BillingPlanResource (nullable-aware)
  Checkout-->>UI: render line items and toggles (use presence checks like Boolean(annualMonthlyFee))
  alt payment required
    UI->>API: confirmCheckout (payload uses paymentMethodId)
    API-->>UI: success / failure
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas to focus on:

  • Consistency between packages/shared type changes and all callers (frontend + backend).
  • Backend fromJSON nullable/optional normalization (CommercePlan, Feature, CommerceSubscriptionItem).
  • UI branches that switched from numeric amount checks to presence checks and places using non-null assertions.
  • Renamed checkout param (paymentSourceId → paymentMethodId) and related confirmCheckout usages.
  • Tests updated to null fixtures—ensure runtime shapes match new mappers.

Poem

🐰 I hop through fields and nullable trails,
Coaxing types where absence prevails.
I guard each amount and payment key,
A tiny rabbit, mapping safely.
Cheers to tidy code and fuller tails. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: updating the supported API version to 2025-11-10 across backend and clerk-js packages.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elef/bill-1377-update-clerk-js-and-clerkbackend-to-use-the-new-api-versions

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 56c638f and 1d1b602.

📒 Files selected for processing (1)
  • packages/shared/src/react/__tests__/commerce.test.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
**/*.test.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.test.{jsx,tsx}: Use React Testing Library
Test component behavior, not implementation
Use proper test queries
Implement proper test isolation
Use proper test coverage
Test component interactions
Use proper test data
Implement proper test setup
Use proper test cleanup
Implement proper test assertions
Use proper test structure

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/shared/src/react/__tests__/commerce.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: triage
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
packages/shared/src/react/__tests__/commerce.test.tsx (2)

125-125: No issues found; the test fixture correctly reflects type definitions.

The totalDueAfterFreeTrial: null addition at line 125 aligns with the type definition at packages/shared/src/types/billing.ts:681 which specifies totalDueAfterFreeTrial: BillingMoneyAmount | null. The field is properly initialized as null in the test fixture and is correctly used in production code with appropriate null checks.


144-154: The review comment is incorrect; no changes needed.

The test fixture changes are consistent with TypeScript type definitions. Optional fields (marked with ?) correctly use undefined when absent, while fields explicitly typed as nullable (e.g., string | null) correctly use null. The three fields follow this principle: freeTrialEndsAt and imageUrl are optional (Date? and string?), so undefined is correct; organizationId is typed as string | null, so null is correct.


Comment @coderabbitai help to get the list of available commands and usage tips.

@panteliselef panteliselef marked this pull request as ready for review October 29, 2025 17:43
@panteliselef panteliselef changed the title feat(backend, clerk-js): Update the supported API version to 2025-10-01 [WIP] feat(backend, clerk-js): Update the supported API version to 2025-10-01 Oct 29, 2025
@panteliselef panteliselef changed the title [WIP] feat(backend, clerk-js): Update the supported API version to 2025-10-01 feat(backend, clerk-js): Update the supported API version to 2025-10-01 Oct 29, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fb49d29 and e783dd0.

📒 Files selected for processing (2)
  • packages/backend/src/constants.ts (1 hunks)
  • packages/clerk-js/src/core/constants.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/constants.ts
  • packages/backend/src/constants.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/core/constants.ts
  • packages/backend/src/constants.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/core/constants.ts
  • packages/backend/src/constants.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/core/constants.ts
  • packages/backend/src/constants.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/core/constants.ts
  • packages/backend/src/constants.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/core/constants.ts
  • packages/backend/src/constants.ts
🔇 Additional comments (1)
packages/clerk-js/src/core/constants.ts (1)

57-57: Version update is properly integrated and tested.

The verification confirms that SUPPORTED_FAPI_VERSION = '2025-10-01' is correctly implemented:

  • The version is consistently passed as __clerk_api_version query parameter in all API requests via fapiClient.buildUrl()
  • Comprehensive test coverage (15+ test cases in fapiClient.test.ts) confirms the version is correctly appended to request URLs
  • Type definitions in @clerk/types are generically designed to handle versioned API responses without requiring version-specific schema switching

The frontend does not handle version-dependent response schema changes—this responsibility belongs to the backend, which validates and returns appropriate responses based on the __clerk_api_version parameter. The generic type system ensures compatibility across API versions.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e783dd0 and 263b29b.

📒 Files selected for processing (1)
  • .changeset/hot-jars-smell.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/**

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Automated releases must use Changesets.

Files:

  • .changeset/hot-jars-smell.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 29, 2025

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7095

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7095

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7095

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7095

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7095

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7095

@clerk/elements

npm i https://pkg.pr.new/@clerk/elements@7095

@clerk/clerk-expo

npm i https://pkg.pr.new/@clerk/clerk-expo@7095

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7095

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7095

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7095

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7095

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7095

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7095

@clerk/clerk-react

npm i https://pkg.pr.new/@clerk/clerk-react@7095

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7095

@clerk/remix

npm i https://pkg.pr.new/@clerk/remix@7095

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7095

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7095

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7095

@clerk/themes

npm i https://pkg.pr.new/@clerk/themes@7095

@clerk/types

npm i https://pkg.pr.new/@clerk/types@7095

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7095

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7095

commit: 1d1b602

@panteliselef panteliselef changed the title feat(backend, clerk-js): Update the supported API version to 2025-10-01 [WIP] feat(backend, clerk-js): Update the supported API version to 2025-10-01 Oct 29, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (1)
packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx (1)

159-163: Consider adding non-null assertion for type safety.

The planFee calculation at line 162 may cause a TypeScript error because plan.annualMonthlyFee is inferred as BillingMoneyAmount | null, even though the logic ensures it's non-null when reached.

Consider updating the code to match the pattern in PricingTableDefault.tsx:

-                const planFee = !plan.annualMonthlyFee
-                  ? plan.fee
-                  : planPeriod === 'annual'
-                    ? plan.annualMonthlyFee
-                    : plan.fee;
+                const planFee = !plan.annualMonthlyFee
+                  ? plan.fee
+                  : planPeriod === 'annual'
+                    ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+                      plan.annualMonthlyFee!
+                    : plan.fee;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 263b29b and 6ac7b4d.

📒 Files selected for processing (13)
  • packages/backend/src/tokens/__tests__/handshake.test.ts (1 hunks)
  • packages/clerk-js/src/core/resources/BillingPlan.ts (2 hunks)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts (1 hunks)
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1 hunks)
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx (2 hunks)
  • packages/types/src/billing.ts (1 hunks)
  • packages/types/src/json.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/backend/src/tokens/tests/handshake.test.ts
🧰 Additional context used
📓 Path-based instructions (9)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
🧬 Code graph analysis (2)
packages/clerk-js/src/core/resources/BillingPlan.ts (2)
packages/types/src/billing.ts (1)
  • BillingMoneyAmount (615-632)
packages/clerk-js/src/utils/billing.ts (1)
  • billingMoneyAmountFromJSON (10-17)
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (1)
packages/clerk-js/src/ui/contexts/components/Plans.tsx (1)
  • normalizeFormatted (27-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (12)
packages/clerk-js/src/core/resources/BillingPlan.ts (2)

11-12: LGTM: Nullable field declarations are correct.

Making annualFee and annualMonthlyFee nullable with default null properly reflects the API changes and allows plans without annual pricing options.


44-45: LGTM: Proper null-safe JSON deserialization.

The ternary operator correctly handles nullable annual pricing fields, setting them to null when absent from the API response.

packages/types/src/json.ts (1)

637-638: LGTM: Type definitions correctly reflect nullable annual pricing.

Making annual_fee and annual_monthly_fee nullable in the JSON type definitions properly aligns with the API version 2025-10-01 changes.

packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts (1)

37-37: LGTM: Presence-based check is safer.

Switching from plan.annualMonthlyFee.amount > 0 to Boolean(plan.annualMonthlyFee) is the correct approach for nullable fields. This avoids potential null reference errors and properly handles the updated data model.

packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (1)

377-378: LGTM: Safe presence check for switchability.

Using Boolean(subscription.plan.annualMonthlyFee) is the correct approach to check if annual pricing is available before allowing period switching.

packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx (2)

229-234: LGTM: Proper null handling with fallback.

This code correctly checks for annualMonthlyFee existence before using it, falling back to plan.fee when it's null. This is the safe pattern that should be used throughout the codebase.


336-364: LGTM: Conditional rendering based on existence.

Using plan.annualMonthlyFee in a conditional expression properly handles nullable fields. The toggle is only shown when annual pricing is available, with an appropriate notice displayed otherwise.

packages/types/src/billing.ts (1)

134-140: LGTM! Type definitions accurately reflect nullable annual pricing.

The type changes for annualFee and annualMonthlyFee to include | null are well-documented and align with the broader API version update. Since the interface is marked as @experimental, this change is appropriate.

packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx (1)

287-296: LGTM! Non-null assertion is safe in this context.

The fee calculation correctly handles nullable annualMonthlyFee. The non-null assertion on line 294 is safe because planSupportsAnnual is only true when annualMonthlyFee is truthy.

packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx (2)

63-63: Consistent with presence-based logic across the PR.

The change to Boolean(plan.annualMonthlyFee) aligns with the nullable type updates. This enables billing cycle controls when annualMonthlyFee exists, regardless of amount.


255-297: LGTM! Conditional rendering correctly handles nullable field.

The truthiness check plan.annualMonthlyFee ? (...) appropriately renders the annual billing notice only when annual pricing exists.

packages/clerk-js/src/ui/contexts/components/Plans.tsx (1)

216-216: LGTM! Correctly checks for annual pricing eligibility.

The use of Boolean(plan?.annualMonthlyFee) with optional chaining safely checks whether a plan supports annual billing.

Comment on lines +42 to +46
const fee =
planPeriod === 'month'
? plan.fee
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
plan.annualMonthlyFee!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unsafe non-null assertion could cause runtime errors.

Same issue as in PaymentAttemptPage: using plan.annualMonthlyFee! without verification could throw if the field is null.

Apply this safer pattern:

-  const fee =
-    planPeriod === 'month'
-      ? plan.fee
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        plan.annualMonthlyFee!;
+  const fee =
+    planPeriod === 'month' || !plan.annualMonthlyFee
+      ? plan.fee
+      : plan.annualMonthlyFee;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fee =
planPeriod === 'month'
? plan.fee
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
plan.annualMonthlyFee!;
const fee =
planPeriod === 'month' || !plan.annualMonthlyFee
? plan.fee
: plan.annualMonthlyFee;
🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx around lines 42
to 46, the code uses an unsafe non-null assertion plan.annualMonthlyFee! which
can throw at runtime if that field is null; replace the assertion with a guarded
access and explicit handling: check whether plan.annualMonthlyFee is defined
before using it (e.g., use a conditional/fallback value or throw a descriptive
error), or compute fee via a nullish coalescing/fallback expression so fee is
never assigned an unchecked null value; ensure TypeScript types reflect the
runtime check so there are no non-null assertions left.

Comment on lines 217 to +221
const fee =
subscriptionItem.planPeriod === 'month' ? subscriptionItem.plan.fee : subscriptionItem.plan.annualMonthlyFee;
subscriptionItem.planPeriod === 'month'
? subscriptionItem.plan.fee
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
subscriptionItem.plan.annualMonthlyFee!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unsafe non-null assertion could cause runtime errors.

The code uses a non-null assertion (plan.annualMonthlyFee!) without first verifying that annualMonthlyFee exists. Since this field is now nullable (as per the type changes), this could throw a runtime error if the API returns null.

Apply this defensive pattern instead:

-  const fee =
-    subscriptionItem.planPeriod === 'month'
-      ? subscriptionItem.plan.fee
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        subscriptionItem.plan.annualMonthlyFee!;
+  const fee =
+    subscriptionItem.planPeriod === 'month' || !subscriptionItem.plan.annualMonthlyFee
+      ? subscriptionItem.plan.fee
+      : subscriptionItem.plan.annualMonthlyFee;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fee =
subscriptionItem.planPeriod === 'month' ? subscriptionItem.plan.fee : subscriptionItem.plan.annualMonthlyFee;
subscriptionItem.planPeriod === 'month'
? subscriptionItem.plan.fee
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
subscriptionItem.plan.annualMonthlyFee!;
const fee =
subscriptionItem.planPeriod === 'month' || !subscriptionItem.plan.annualMonthlyFee
? subscriptionItem.plan.fee
: subscriptionItem.plan.annualMonthlyFee;
🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
around lines 217-221, the code uses a non-null assertion on
subscriptionItem.plan.annualMonthlyFee which is now nullable; replace the unsafe
assertion with a defensive check: if annualMonthlyFee is present use it,
otherwise fall back to a safe default (e.g., plan.fee, 0, or a user-friendly
placeholder) or throw/log a clear error before using the value so no runtime
null access occurs. Ensure the code handles both month and non-month periods
without the `!` operator and preserves type-safety.

Comment on lines +412 to +415
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
price: normalizeFormatted(subscription.plan.annualFee!.amountFormatted),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
currency: subscription.plan.annualFee!.currencySymbol,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unsafe non-null assertion in localization keys.

The non-null assertions for subscription.plan.annualFee! are unsafe. If annualFee is null, this will throw at runtime when constructing the localization string.

Since this code path only executes when isSwitchable is true (which checks for annualMonthlyFee), you should also verify annualFee exists:

+      // Ensure annualFee exists before using it
+      if (!subscription.plan.annualFee) {
+        return null;
+      }
       isSwitchable
         ? {
             label:
               subscription.planPeriod === 'month'
                 ? localizationKeys('billing.switchToAnnualWithAnnualPrice', {
-                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                    price: normalizeFormatted(subscription.plan.annualFee!.amountFormatted),
-                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                    currency: subscription.plan.annualFee!.currencySymbol,
+                    price: normalizeFormatted(subscription.plan.annualFee.amountFormatted),
+                    currency: subscription.plan.annualFee.currencySymbol,
                   })

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx around
lines 412 to 415, the code uses non-null assertions on
subscription.plan.annualFee which can throw if annualFee is null; add a guard
that verifies subscription.plan.annualFee exists before accessing
amountFormatted and currencySymbol (e.g., if (!subscription.plan.annualFee)
return/skip building the localized string or provide safe fallbacks), and
replace the non-null assertions with safe access or validated locals so the
localization string is only built when annualFee is present.

Comment on lines +485 to +489
const fee =
subscription.planPeriod === 'month'
? subscription.plan.fee
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
subscription.plan.annualFee!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unsafe non-null assertion in fee calculation.

Using subscription.plan.annualFee! without verification could throw if the field is null.

Apply this safer pattern:

-  const fee =
-    subscription.planPeriod === 'month'
-      ? subscription.plan.fee
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        subscription.plan.annualFee!;
+  const fee =
+    subscription.planPeriod === 'month' || !subscription.plan.annualFee
+      ? subscription.plan.fee
+      : subscription.plan.annualFee;
🤖 Prompt for AI Agents
In packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx around
lines 485 to 489, the code uses a non-null assertion
subscription.plan.annualFee! which can throw if annualFee is null/undefined;
replace the assertion with a safe check — use optional chaining and a fallback
(e.g., subscription.plan.annualFee ?? 0 or another sensible default), or
explicitly handle the missing value (throw a descriptive error or return early).
Ensure fee is computed like: if planPeriod === 'month' use
subscription.plan.fee, otherwise use subscription.plan.annualFee ?? <fallback>
so no non-null assertion is needed.

@panteliselef panteliselef force-pushed the elef/bill-1377-update-clerk-js-and-clerkbackend-to-use-the-new-api-versions branch from 6ac7b4d to 52a2409 Compare October 29, 2025 21:08
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (4)
packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1)

42-46: Unsafe non-null assertion could cause runtime errors.

The non-null assertion plan.annualMonthlyFee! on line 46 is unsafe. Since annualMonthlyFee is now nullable (as seen in the type updates in packages/types/src/billing.ts), this will throw a runtime error if the field is null.

Apply the safer pattern suggested in the previous review:

-  const fee =
-    planPeriod === 'month'
-      ? plan.fee
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        plan.annualMonthlyFee!;
+  const fee =
+    planPeriod === 'month' || !plan.annualMonthlyFee
+      ? plan.fee
+      : plan.annualMonthlyFee;
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (2)

412-415: Unsafe non-null assertion in localization keys.

The non-null assertions for subscription.plan.annualFee! on lines 413 and 415 are unsafe. If annualFee is null, this will throw at runtime.

As suggested in the previous review, add a guard before this code path:

+      // Ensure annualFee exists before using it
+      if (subscription.planPeriod === 'month' && !subscription.plan.annualFee) {
+        return [];
+      }
       isSwitchable
         ? {
             label:
               subscription.planPeriod === 'month'
                 ? localizationKeys('billing.switchToAnnualWithAnnualPrice', {
-                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                    price: normalizeFormatted(subscription.plan.annualFee!.amountFormatted),
-                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                    currency: subscription.plan.annualFee!.currencySymbol,
+                    price: normalizeFormatted(subscription.plan.annualFee.amountFormatted),
+                    currency: subscription.plan.annualFee.currencySymbol,
                   })

485-489: Unsafe non-null assertion in fee calculation.

Using subscription.plan.annualFee! without verification on line 489 could throw if the field is null.

Apply this safer pattern:

-  const fee =
-    subscription.planPeriod === 'month'
-      ? subscription.plan.fee
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        subscription.plan.annualFee!;
+  const fee =
+    subscription.planPeriod === 'month' || !subscription.plan.annualFee
+      ? subscription.plan.fee
+      : subscription.plan.annualFee;
packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx (1)

285-285: Critical: Incorrect logic allows zero-cost annual plans to show annual toggle.

Line 285 changed to check Boolean(annualMonthlyFee) instead of annualMonthlyFee.amount > 0. This breaks the intended behavior: plans with annual pricing set to 0 ({amount: 0, ...}) will now be treated as supporting annual periods when they shouldn't.

The test in pricing-footer-state.spec.ts line 108 explicitly expects: "does not show footer when switching period if annualMonthlyFee is 0".

-  const planSupportsAnnual = Boolean(annualMonthlyFee);
+  const planSupportsAnnual = Boolean(annualMonthlyFee && annualMonthlyFee.amount > 0);

Note: This same pattern also appears in:

  • Plans.tsx (lines 216, 329)
  • pricing-footer-state.ts (line 37)
  • PricingTableMatrix.tsx (lines 63, 159)

Verify and update those locations as well.

Based on learnings

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac7b4d and 52a2409.

📒 Files selected for processing (15)
  • packages/clerk-js/src/core/resources/BillingPlan.ts (2 hunks)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts (1 hunks)
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1 hunks)
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx (2 hunks)
  • packages/clerk-js/src/utils/billing.ts (1 hunks)
  • packages/types/src/billing.ts (1 hunks)
  • packages/types/src/json.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/clerk-js/src/ui/contexts/components/Plans.tsx
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/types/src/json.ts
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
🧰 Additional context used
📓 Path-based instructions (13)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/utils/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/utils/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/utils/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/utils/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/utils/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
packages/**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Unit tests should use Jest or Vitest as the test runner.

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
packages/{clerk-js,elements,themes}/**/*.{test,spec}.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Visual regression testing should be performed for UI components.

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/utils/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/types/src/billing.ts
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
**/*.test.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.test.{jsx,tsx}: Use React Testing Library
Test component behavior, not implementation
Use proper test queries
Implement proper test isolation
Use proper test coverage
Test component interactions
Use proper test data
Implement proper test setup
Use proper test cleanup
Implement proper test assertions
Use proper test structure

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
**/__tests__/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/typescript.mdc)

**/__tests__/**/*.{ts,tsx}: Create type-safe test builders/factories
Use branded types for test isolation
Implement proper mock types that match interfaces

Files:

  • packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx
🧬 Code graph analysis (1)
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (1)
packages/clerk-js/src/ui/contexts/components/Plans.tsx (1)
  • normalizeFormatted (27-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (3)
packages/clerk-js/src/ui/components/SubscriptionDetails/__tests__/SubscriptionDetails.test.tsx (1)

265-266: LGTM! Test data correctly reflects nullable annual pricing.

The change to null values for annualFee and annualMonthlyFee in the Free Plan scenario correctly aligns with the type updates that made these fields nullable. This ensures tests cover the case where annual pricing is not available.

packages/clerk-js/src/ui/components/Plans/__tests__/PlanDetails.test.tsx (1)

224-225: LGTM! Test data correctly reflects nullable annual pricing.

The changes to null values for annualFee and annualMonthlyFee properly test scenarios where annual pricing is unavailable. This aligns with the type updates in packages/types/src/billing.ts that made these fields nullable.

Also applies to: 258-259

packages/clerk-js/src/utils/billing.ts (1)

28-36: The original review comment is based on incorrect reasoning about JavaScript truthiness.

The truthy checks on lines 28, 31, and 34 will not exclude zero-amount values. Since BillingMoneyAmountJSON is an object (e.g., {amount: 0, amountFormatted: '0.00', ...}), and objects are truthy in JavaScript, these conditions will evaluate to true and the assignments will occur. The type definitions confirm these fields are required (not nullable) in BillingCheckoutTotalsJSON and BillingStatementTotalsJSON, and extensive test coverage demonstrates zero-amount objects are expected in the output.

The distinction between the original in check and the new truthy check only matters if the value is null, undefined, or a falsy scalar—not for objects with zero-amount properties inside them.

Likely an incorrect or invalid review comment.

Comment on lines 38 to 39
// WHY `total_due_after_free_trial` and why `proration`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify the purpose of this comment.

The comment suggests uncertainty about total_due_after_free_trial and proration fields. If these fields are part of the API response but not being handled, document why they're excluded or create a task to implement them.

🤖 Prompt for AI Agents
In packages/clerk-js/src/utils/billing.ts around lines 38 to 39, the inline
comment "// WHY `total_due_after_free_trial` and why `proration`" is vague;
replace it with a clear explanation stating whether those fields appear in the
API response and why they are intentionally ignored (e.g., not used by current
billing flow), or if they must be supported, add a TODO with a link/ID to a
tracker ticket to implement handling. Include what the fields represent, the
decision (exclude or implement), and next steps (either remove/comment as
explained or add task to implement parsing/logic).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/types/src/billing.ts (1)

691-703: Changeset must document the breaking change with explicit migration guidance.

The changeset file (./.changeset/hot-jars-smell.md) only states "Update the supported API version to 2025-10-01" but fails to document the breaking change: renaming paymentSourceId to paymentMethodId in ConfirmCheckoutParams.

While the codebase has been correctly updated (no references to the old parameter remain), the changeset lacks the necessary migration guidance that users need to update their code. This differs from the pattern established in v4.93.0, which documented similar billing API renames with clear before/after examples.

Update the changeset to include:

  • Explicit mention of the parameter rename: paymentSourceIdpaymentMethodId
  • Migration guidance: "Rename paymentSourceId to paymentMethodId in all checkout confirm() calls"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 52a2409 and ed3a125.

📒 Files selected for processing (2)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (2 hunks)
  • packages/types/src/billing.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/types/src/billing.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/types/src/billing.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/types/src/billing.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/types/src/billing.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/types/src/billing.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/types/src/billing.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan

Comment on lines +134 to +140
* The annual price of the plan or `null` if the plan is not annual.
*/
annualFee: BillingMoneyAmount;
annualFee: BillingMoneyAmount | null;
/**
* The effective monthly price when billed annually.
* The effective monthly price when billed annually or `null` if the plan is not annual.
*/
annualMonthlyFee: BillingMoneyAmount;
annualMonthlyFee: BillingMoneyAmount | null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that consumer code was updated per previous review findings.

The nullable type change for annualFee and annualMonthlyFee is correct, but a previous review identified specific locations with non-null assertions and unsafe Boolean checks that will break with this change.

Ensure all flagged locations have been fixed before merging:

  • 7 non-null assertion sites (e.g., SubscriptionsList.tsx:157, SubscriptionDetails/index.tsx:413,415,489)
  • 3 unsafe Boolean checks (e.g., PricingTableMatrix.tsx:63, pricing-footer-state.ts:37)

Based on learnings


🏁 Script executed:

#!/bin/bash
# Verify that non-null assertions and unsafe Boolean checks have been addressed

echo "=== Checking for remaining non-null assertions on annual fees ==="
rg -n 'annualFee!' --type=ts -C2

echo ""
echo "=== Checking for remaining non-null assertions on annualMonthlyFee ==="
rg -n 'annualMonthlyFee!' --type=ts -C2

echo ""
echo "=== Checking for unsafe Boolean checks without null guards ==="
rg -nP 'if\s*\([^)]*\.(annualFee|annualMonthlyFee)\)' --type=ts -C2

echo ""
echo "=== Checking for direct property access without null checks ==="
rg -n '\.(annualFee|annualMonthlyFee)\.(amount|amountFormatted|currency)' --type=ts -C3

Length of output: 4581


Address unsafe non-null assertions in consumer code to properly handle nullable annual fees.

The nullable type changes for annualFee and annualMonthlyFee are correct, but consumer code still uses non-null assertions (!) that bypass TypeScript's type safety. These should be replaced with proper null checks or type guards:

  • SubscriptionsList.tsx:157: subscription.plan.annualFee!
  • SubscriptionDetails/index.tsx:413, 415, 489: annualFee! and property access
  • PricingTableDefault.tsx:294: plan.annualMonthlyFee!
  • PaymentAttemptPage.tsx:221: plan.annualMonthlyFee!
  • CheckoutForm.tsx:46: plan.annualMonthlyFee!

While runtime logic (e.g., planPeriod === 'annual') ensures these values exist in practice, the type system doesn't capture these guarantees. Refactor to use discriminated unions, type predicates, or explicit null checks instead of non-null assertions.

🤖 Prompt for AI Agents
In packages/types/src/billing.ts around lines 134-140, avoid forcing non-null
with `!` in consumers by either making the Plan type a discriminated union
(e.g., separate MonthlyPlan and AnnualPlan where annualFee/annualMonthlyFee
exist only on AnnualPlan with a literal period discriminator) or keep the
nullable fields but update the listed consumer files to narrow the type before
access: replace `!` usages with explicit null checks or type guards (e.g., if
(plan.period === 'annual') { /* safe to access annualFee/annualMonthlyFee */ })
so TypeScript can verify safety and remove the non-null assertions in
SubscriptionsList.tsx:157, SubscriptionDetails/index.tsx:413,415,489,
PricingTableDefault.tsx:294, PaymentAttemptPage.tsx:221, and
CheckoutForm.tsx:46.

…d-clerkbackend-to-use-the-new-api-versions

# Conflicts:
#	packages/types/src/json.ts
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (7)
packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1)

61-70: Drop the non-null assertion on plan.annualMonthlyFee.
This is the same crash we flagged in the earlier review: the annual-plan path still dereferences plan.annualMonthlyFee!, so when the new API returns null the checkout totals render blows up before we can show the form. Guard the value instead of asserting so we fail soft and keep the UI usable.

Apply this diff:

-  const fee =
-    planPeriod === 'month'
-      ? plan.fee
-      : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-        plan.annualMonthlyFee!;
+  const fee =
+    planPeriod === 'month'
+      ? plan.fee
+      : plan.annualMonthlyFee ?? plan.fee;
packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (1)

217-221: Critical: Unsafe non-null assertion can cause runtime errors.

The non-null assertion annualMonthlyFee! suppresses TypeScript warnings but does not prevent runtime errors when the field is null. Since annualMonthlyFee is now nullable (per the API version update), this code will throw if planPeriod is not 'month' but annualMonthlyFee is null.

Apply this defensive pattern:

 const fee =
-  subscriptionItem.planPeriod === 'month'
+  subscriptionItem.planPeriod === 'month' || !subscriptionItem.plan.annualMonthlyFee
     ? subscriptionItem.plan.fee
-    : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      subscriptionItem.plan.annualMonthlyFee!;
+    : subscriptionItem.plan.annualMonthlyFee;
packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx (2)

285-285: Critical: Boolean check breaks zero-cost annual pricing.

The logic changed from checking annualMonthlyFee.amount > 0 to Boolean(annualMonthlyFee). This treats plans with { amount: 0, ... } as supporting annual periods, but the test in pricing-footer-state.spec.ts line 108 ("does not show footer when switching period if annualMonthlyFee is 0") confirms zero-cost annual plans should not enable the toggle.

Apply this fix:

-const planSupportsAnnual = Boolean(annualMonthlyFee);
+const planSupportsAnnual = Boolean(annualMonthlyFee?.amount);

292-295: Critical: Unsafe non-null assertion when annual pricing enabled.

If planSupportsAnnual is true but annualMonthlyFee is somehow null (data inconsistency), the non-null assertion will not prevent runtime errors.

Apply this safer pattern:

-  return planPeriod === 'annual'
-    ? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      plan.annualMonthlyFee!
-    : plan.fee;
+  if (planPeriod === 'annual' && plan.annualMonthlyFee) {
+    return plan.annualMonthlyFee;
+  }
+  return plan.fee;
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (3)

377-379: Critical: Inconsistent field check - annualMonthlyFee vs annualFee.

Line 377 checks subscription.plan.annualMonthlyFee to determine switchability, but lines 412-415 and 485-489 use non-null assertions on subscription.plan.annualFee. These are different fields—one being present doesn't guarantee the other exists. This mismatch can cause runtime errors.

Either verify both fields or use the same field consistently:

 const isSwitchable =
   ((subscription.planPeriod === 'month' && Boolean(subscription.plan.annualMonthlyFee)) ||
     subscription.planPeriod === 'annual') &&
   subscription.status !== 'past_due';
+
+// Verify annualFee exists when needed for switchable logic
+if (isSwitchable && subscription.planPeriod === 'month' && !subscription.plan.annualFee) {
+  // Handle missing annualFee
+}

412-415: Critical: Unsafe non-null assertion in localization keys.

The non-null assertions subscription.plan.annualFee! will throw if annualFee is null. Since the switchability check verifies annualMonthlyFee (not annualFee), this field may be null when accessed.

Add a guard before building the localization string:

+  if (isSwitchable && subscription.planPeriod === 'month' && !subscription.plan.annualFee) {
+    return null; // or provide fallback
+  }
+
   isSwitchable
     ? {
         label:
           subscription.planPeriod === 'month'
             ? localizationKeys('billing.switchToAnnualWithAnnualPrice', {
-                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                price: normalizeFormatted(subscription.plan.annualFee!.amountFormatted),
-                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                currency: subscription.plan.annualFee!.currencySymbol,
+                price: normalizeFormatted(subscription.plan.annualFee.amountFormatted),
+                currency: subscription.plan.annualFee.currencySymbol,
               })

485-489: Critical: Unsafe non-null assertion in fee calculation.

Using subscription.plan.annualFee! without verification will throw if the field is null.

Apply this safer pattern:

 const fee =
-  subscription.planPeriod === 'month'
+  subscription.planPeriod === 'month' || !subscription.plan.annualFee
     ? subscription.plan.fee
-    : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-      subscription.plan.annualFee!;
+    : subscription.plan.annualFee;
🧹 Nitpick comments (2)
packages/clerk-js/src/core/resources/BillingPayer.ts (1)

30-33: Extract date parsing logic to a helper function.

The nested ternary logic for preserving undefined vs null semantics when parsing dates is correct but complex and duplicated. Extract it to a reusable helper function to improve readability and maintainability.

Consider adding this helper to @/utils/date:

// In @/utils/date
export function parseOptionalEpoch(epoch: number | null | undefined): Date | null | undefined {
  return epoch === undefined ? undefined : epoch === null ? null : unixEpochToDate(epoch);
}

Then simplify the fromJSON method:

-    this.createdAt =
-      data.created_at === undefined ? undefined : data.created_at === null ? null : unixEpochToDate(data.created_at);
-    this.updatedAt =
-      data.updated_at === undefined ? undefined : data.updated_at === null ? null : unixEpochToDate(data.updated_at);
+    this.createdAt = parseOptionalEpoch(data.created_at);
+    this.updatedAt = parseOptionalEpoch(data.updated_at);
packages/backend/src/api/resources/Feature.ts (1)

21-29: Update JSDoc comments to reflect nullability.

The constructor parameters for description and avatarUrl are now nullable, but the JSDoc comments at lines 19 and 27 don't indicate this. Consider updating them to clarify when these values might be null.

Apply this diff to update the JSDoc:

     /**
      * The description of the feature.
+     * @remarks This field may be `null` if no description is provided.
      */
     readonly description: string | null,
     /**
      * The URL-friendly identifier of the feature.
      */
     readonly slug: string,
     /**
      * The URL of the feature's avatar image.
+     * @remarks This field may be `null` if no avatar is available.
      */
     readonly avatarUrl: string | null,
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ed3a125 and 6aba342.

📒 Files selected for processing (20)
  • packages/backend/src/api/resources/CommercePlan.ts (4 hunks)
  • packages/backend/src/api/resources/CommerceSubscription.ts (1 hunks)
  • packages/backend/src/api/resources/Feature.ts (1 hunks)
  • packages/backend/src/api/resources/JSON.ts (3 hunks)
  • packages/clerk-js/src/core/constants.ts (1 hunks)
  • packages/clerk-js/src/core/resources/BillingPayer.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingPlan.ts (2 hunks)
  • packages/clerk-js/src/core/resources/Feature.ts (2 hunks)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx (6 hunks)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (6 hunks)
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx (1 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts (1 hunks)
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (3 hunks)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/clerk-js/src/ui/components/Subscriptions/SubscriptionsList.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableMatrix.tsx
  • packages/clerk-js/src/ui/components/PricingTable/utils/pricing-footer-state.ts
  • packages/clerk-js/src/core/constants.ts
🧰 Additional context used
📓 Path-based instructions (9)
packages/clerk-js/src/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/clerk-js-ui.mdc)

packages/clerk-js/src/ui/**/*.{ts,tsx}: Element descriptors should always be camelCase
Use element descriptors in UI components to enable consistent theming and styling via appearance.elements
Element descriptors should generate unique, stable CSS classes for theming
Element descriptors should handle state classes (e.g., cl-loading, cl-active, cl-error, cl-open) automatically based on component state
Do not render hard-coded values; all user-facing strings must be localized using provided localization methods
Use the useLocalizations hook and localizationKeys utility for all text and error messages
Use the styled system (sx prop, theme tokens, responsive values) for custom component styling
Use useCardState for card-level state, useFormState for form-level state, and useLoadingStatus for loading states
Always use handleError utility for API errors and use translateError for localized error messages
Use useFormControl for form field state, implement proper validation, and handle loading and error states in forms
Use localization keys for all form labels and placeholders
Use element descriptors for consistent styling and follow the theme token system
Use the Card and FormContainer patterns for consistent UI structure

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/backend/src/api/resources/JSON.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/backend/src/api/resources/JSON.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/backend/src/api/resources/JSON.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/backend/src/api/resources/JSON.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/backend/src/api/resources/JSON.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{jsx,tsx}: Use error boundaries in React components
Minimize re-renders in React components

**/*.{jsx,tsx}: Always use functional components with hooks instead of class components
Follow PascalCase naming for components: UserProfile, NavigationMenu
Keep components focused on a single responsibility - split large components
Limit component size to 150-200 lines; extract logic into custom hooks
Use composition over inheritance - prefer smaller, composable components
Export components as named exports for better tree-shaking
One component per file with matching filename and component name
Use useState for simple state management
Use useReducer for complex state logic
Implement proper state initialization
Use proper state updates with callbacks
Implement proper state cleanup
Use Context API for theme/authentication
Implement proper state selectors
Use proper state normalization
Implement proper state persistence
Use React.memo for expensive components
Implement proper useCallback for handlers
Use proper useMemo for expensive computations
Implement proper virtualization for lists
Use proper code splitting with React.lazy
Implement proper cleanup in useEffect
Use proper refs for DOM access
Implement proper event listener cleanup
Use proper abort controllers for fetch
Implement proper subscription cleanup
Use proper HTML elements
Implement proper ARIA attributes
Use proper heading hierarchy
Implement proper form labels
Use proper button types
Implement proper focus management
Use proper keyboard shortcuts
Implement proper tab order
Use proper skip links
Implement proper focus traps
Implement proper error boundaries
Use proper error logging
Implement proper error recovery
Use proper error messages
Implement proper error fallbacks
Use proper form validation
Implement proper error states
Use proper error messages
Implement proper form submission
Use proper form reset
Use proper component naming
Implement proper file naming
Use proper prop naming
Implement proper...

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/backend/src/api/resources/CommerceSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPlan.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/backend/src/api/resources/JSON.ts
  • packages/backend/src/api/resources/Feature.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/backend/src/api/resources/CommercePlan.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

**/*.tsx: Use proper type definitions for props and state
Leverage TypeScript's type inference where possible
Use proper event types for handlers
Implement proper generic types for reusable components
Use proper type guards for conditional rendering

Files:

  • packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/ui/components/PricingTable/PricingTableDefault.tsx
  • packages/clerk-js/src/ui/components/PaymentAttempts/PaymentAttemptPage.tsx
  • packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
🧬 Code graph analysis (10)
packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx (1)
packages/shared/src/types/billing.ts (1)
  • BillingPaymentMethodResource (276-347)
packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (1)
packages/shared/src/types/billing.ts (1)
  • BillingPaymentMethodResource (276-347)
packages/clerk-js/src/ui/components/SubscriptionDetails/index.tsx (1)
packages/clerk-js/src/ui/contexts/components/Plans.tsx (1)
  • normalizeFormatted (27-29)
packages/backend/src/api/resources/CommerceSubscription.ts (1)
packages/backend/src/api/resources/CommerceSubscriptionItem.ts (1)
  • BillingSubscriptionItem (11-128)
packages/clerk-js/src/core/resources/BillingPlan.ts (2)
packages/shared/src/types/billing.ts (2)
  • BillingMoneyAmount (637-654)
  • BillingPayerResourceType (62-62)
packages/clerk-js/src/utils/billing.ts (1)
  • billingMoneyAmountFromJSON (10-17)
packages/backend/src/api/resources/JSON.ts (1)
packages/shared/src/types/json.ts (1)
  • BillingMoneyAmountJSON (783-788)
packages/backend/src/api/resources/Feature.ts (2)
packages/backend/src/api/resources/JSON.ts (1)
  • FeatureJSON (834-840)
packages/clerk-js/src/core/resources/Feature.ts (1)
  • Feature (5-30)
packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethods.tsx (1)
packages/shared/src/types/billing.ts (1)
  • BillingPaymentMethodResource (276-347)
packages/backend/src/api/resources/CommercePlan.ts (3)
packages/shared/src/types/billing.ts (1)
  • BillingMoneyAmount (637-654)
packages/backend/src/api/resources/JSON.ts (1)
  • BillingPlanJSON (845-861)
packages/backend/src/api/resources/Feature.ts (1)
  • Feature (8-35)
packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (1)
packages/shared/src/types/billing.ts (2)
  • BillingPaymentMethodResource (276-347)
  • BillingPaymentMethodStatus (222-222)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (9)
packages/backend/src/api/resources/CommerceSubscription.ts (1)

76-76: LGTM! Good defensive pattern.

The null-coalescing operator ensures safe handling when subscription_items is absent from the API response, preventing runtime errors during mapping.

packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx (1)

230-234: LGTM! Excellent defensive pattern.

The presence check for annualMonthlyFee before access (lines 230-231) and before rendering the toggle (line 336) prevents runtime errors and correctly handles plans without annual pricing. This is the proper approach for nullable fields.

Also applies to: 336-364

packages/backend/src/api/resources/CommercePlan.ts (2)

72-75: LGTM! Defensive null handling.

The formatAmountJSON helper correctly returns null for falsy inputs (lines 72-75), and the null-coalescing operators on lines 89 and 100 provide safe defaults for optional fields.

Also applies to: 89-89, 100-100


94-96: The review comment is based on an incorrect assumption about the API contract.

The BillingPlanJSON interface defines fee: BillingMoneyAmountJSON; as a required field (not optional and not nullable), whereas the optional fields like annual_fee are properly marked with ? and | null. Since data.fee is guaranteed to be non-null from the API contract, the non-null assertion at line 94 is safe and justified.

While the formatAmountJSON function accepts nullable inputs (to handle both required and optional fields), the actual call with data.fee will never result in a null return. The assertion correctly reflects the caller's knowledge of the API contract.

packages/clerk-js/src/core/resources/Feature.ts (1)

8-10: LGTM! Consistent nullable field handling.

The nullable field declarations with null defaults (lines 8, 10) paired with null-coalescing assignment (lines 24, 26) provide safe, predictable behavior when fields are absent from API responses.

Also applies to: 24-26

packages/clerk-js/src/core/resources/BillingPlan.ts (1)

16-18: LGTM! Well-structured nullable field pattern.

The nullable field declarations with null defaults (lines 16-18, 25) combined with conditional transformations (lines 43-44) and null-coalescing (lines 45, 52) provide consistent, safe handling of optional billing plan fields.

Also applies to: 25-25, 43-45, 52-52

packages/backend/src/api/resources/JSON.ts (2)

889-889: LGTM - Nullable lifetime_paid field.

The lifetime_paid field is now nullable but still required (no ? operator). This correctly models that the field must always be present in the response but can have a null value (e.g., when no payments have been made yet).


837-839: Nullability changes verified and properly handled downstream.

The changes to FeatureJSON making description and avatar_url optional and nullable (lines 837, 839) are correctly applied. Verification confirms:

  • Backend Feature.fromJSON() uses defensive nullish coalescing (??) to safely convert undefined to null
  • Frontend PlanDetails.tsx includes proper conditional checks (feature.description ?) before rendering
  • No unsafe direct property access patterns found in non-test code

The implementation is sound and ready.

packages/backend/src/api/resources/Feature.ts (1)

33-33: LGTM - Proper null coalescing in fromJSON.

The use of ?? null ensures that undefined values are normalized to null, which is consistent with the type declarations (string | null). This defensive approach prevents undefined from leaking into properties that should be explicitly null.

Comment on lines 851 to 860
description?: string | null;
is_default: boolean;
is_recurring: boolean;
has_base_fee: boolean;
publicly_visible: boolean;
fee: BillingMoneyAmountJSON;
annual_fee: BillingMoneyAmountJSON;
annual_monthly_fee: BillingMoneyAmountJSON;
annual_fee?: BillingMoneyAmountJSON | null;
annual_monthly_fee?: BillingMoneyAmountJSON | null;
for_payer_type: 'org' | 'user';
features: FeatureJSON[];
features?: FeatureJSON[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify impact of billing plan field nullability changes.

The changes make several previously required billing fields optional and/or nullable:

  • description: optional + nullable
  • annual_fee, annual_monthly_fee: optional + nullable (previously required)
  • features: optional (previously required array)

The removal of required status from annual_fee and annual_monthly_fee is a significant breaking change. Verify that all consumers check for null/undefined before accessing these fields.


🏁 Script executed:

#!/bin/bash
# Description: Find usages of BillingPlanJSON fields to check for null safety

# Search for annual_fee and annual_monthly_fee access patterns
rg -nP --type=ts --type=tsx -C3 '\b(plan|billing)\.annual_(fee|monthly_fee)\b' -g '!**/test/**' -g '!**/*.test.ts'

# Search for features array access
rg -nP --type=ts --type=tsx -C3 '\b(plan|billing)\.features(\[|\.)' -g '!**/test/**' -g '!**/*.test.ts'

Length of output: 55


I'll fix the script syntax and re-verify the field usages in the codebase.


🏁 Script executed:

#!/bin/bash
# Description: Find usages of BillingPlanJSON fields to check for null safety
# Fixed: Use glob patterns instead of unrecognized type flags

# Search for annual_fee and annual_monthly_fee access patterns in TypeScript files
rg -nP -C3 '\b(plan|billing)\.annual_(fee|monthly_fee)\b' --glob '*.ts' --glob '*.tsx' -g '!**/test/**' -g '!**/*.test.ts'

# Search for features array access
rg -nP -C3 '\b(plan|billing)\.features(\[|\.)' --glob '*.ts' --glob '*.tsx' -g '!**/test/**' -g '!**/*.test.ts'

# Also search for optional chaining patterns which might indicate null safety
rg -nP -C3 '\b(plan|billing)\?.annual_(fee|monthly_fee)' --glob '*.ts' --glob '*.tsx' -g '!**/test/**' -g '!**/*.test.ts'

Length of output: 3348


Let me search more broadly for the annual fee fields and verify the type definitions:


🏁 Script executed:

#!/bin/bash
# Search for broader annual_fee patterns
rg -nP -C2 'annual_fee|annual_monthly_fee' --glob '*.ts' --glob '*.tsx' -g '!**/test/**' -g '!**/*.test.ts' | head -50

# Find the BillingPlanJSON type definition
rg -nP -C10 'interface BillingPlanJSON|type BillingPlanJSON' --glob '*.ts' --glob '*.tsx'

# Check for any null/undefined guards on plan.features
rg -nP -C3 'plan\.features\s*\?' --glob '*.ts' --glob '*.tsx' -g '!**/test/**' -g '!**/*.test.ts'
rg -nP -C3 'plan\.features\s*\|\|' --glob '*.ts' --glob '*.tsx' -g '!**/test/**' -g '!**/*.test.ts'

Length of output: 5493


Let me check for additional annual_fee usages in the backend:


🏁 Script executed:

#!/bin/bash
# Search for formatAmountJSON calls with annual_fee/annual_monthly_fee
rg -nP -C5 'formatAmountJSON\s*\(\s*data\.(annual_fee|annual_monthly_fee)' --glob '*.ts' --glob '*.tsx'

# Check if there are type guards or defaults being set for features
rg -nP -C3 'features\s*\?\?' --glob '*.ts' --glob '*.tsx' -g '!**/test/**'

# Search for any feature array defaults or initialization
rg -nP -C2 '\[\]\s*as.*Feature|Feature\[\].*=' --glob '*.ts' --glob '*.tsx' | head -30

Length of output: 1664


Fix inconsistent null handling for optional billing plan fields.

The change makes annual_fee, annual_monthly_fee, and features optional, but the implementation is inconsistent:

  • CommercePlan.ts lines 97-98: formatAmountJSON(data.annual_fee) and formatAmountJSON(data.annual_monthly_fee) lack null coalescing. Compare to line 100 where features uses data.features ?? []. Apply the same pattern: formatAmountJSON(data.annual_fee ?? null) and formatAmountJSON(data.annual_monthly_fee ?? null) (or appropriate fallback).

  • PricingTableMatrix.tsx:378, PricingTableDefault.tsx:133/431/456: Multiple accesses to plan.features without optional chaining (?.) or null guards. These will throw if features is undefined.

🤖 Prompt for AI Agents
In packages/backend/src/api/resources/JSON.ts lines 851-860 and related places,
fix inconsistent null handling for optional billing plan fields: in
CommercePlan.ts around lines 97-100, wrap calls to formatAmountJSON with a
null-coalescing fallback (e.g. call formatAmountJSON(data.annual_fee ?? null)
and formatAmountJSON(data.annual_monthly_fee ?? null)) to mirror the existing
features fallback; in PricingTableMatrix.tsx line ~378 and
PricingTableDefault.tsx lines ~133, ~431, ~456, guard accesses to plan.features
with optional chaining or explicit null checks (e.g. plan.features ?? [] or
plan.features?.map/length checks) so code never assumes features is defined.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/clerk-js/src/core/modules/billing/namespace.ts (1)

32-36: LGTM! Consider adding JSDoc documentation.

The signature change to accept orgId?: string | null correctly aligns with the API version update to 2025-10-01 and broader nullability support. The implementation properly handles both null and undefined with the truthy check on line 34, defaulting to /me for both cases.

Consider adding JSDoc documentation for this public static method to improve API discoverability:

+  /**
+   * Constructs a billing API path with optional organization context.
+   * @param subPath - The billing resource subpath (e.g., '/subscription', '/statements')
+   * @param param - Optional parameters
+   * @param param.orgId - Organization ID. When null or undefined, defaults to '/me' prefix for user context.
+   * @returns Complete billing API path
+   */
   static path(subPath: string, param?: { orgId?: string | null }): string {

As per coding guidelines.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6aba342 and d68a042.

📒 Files selected for processing (5)
  • packages/clerk-js/src/core/modules/billing/namespace.ts (1 hunks)
  • packages/clerk-js/src/core/resources/BillingPayment.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingSubscription.ts (0 hunks)
  • packages/shared/src/types/billing.ts (11 hunks)
  • packages/shared/src/types/json.ts (7 hunks)
💤 Files with no reviewable changes (1)
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
🧬 Code graph analysis (2)
packages/clerk-js/src/core/resources/BillingPayment.ts (2)
packages/shared/src/types/billing.ts (1)
  • BillingPaymentMethodResource (276-347)
packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (1)
  • BillingPaymentMethod (17-82)
packages/shared/src/types/json.ts (1)
packages/shared/src/types/billing.ts (2)
  • BillingPayerResourceType (62-62)
  • BillingPaymentMethodStatus (222-222)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (1)
packages/clerk-js/src/core/resources/BillingPayment.ts (1)

21-42: Guard prevents crashes when payment methods are omitted.

Wrapping the BillingPaymentMethod construction behind a truthy check keeps us from instantiating with undefined when the backend omits or nulls payment_method, so the resource stays resilient against the expanded API shape. Nice touch.

@blacksmith-sh

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
packages/clerk-js/src/core/resources/BillingPayer.ts (1)

9-17: Unresolved: Inconsistent null handling across field types.

The past review comments correctly identified this issue, and it remains unresolved. The field declarations suggest three-state semantics (field?: Type | null), but the implementation is inconsistent:

  1. Date fields (lines 30-35): Preserve undefined vs null (three-state)
  2. imageUrl (line 36): Preserves undefined vs null via direct assignment (three-state)
  3. String fields (lines 37-42): Collapse undefined to null using ?? null (two-state)

As noted in previous reviews, this should be made consistent. Either:

  • Option A (Recommended): Remove ?? null from lines 37-42 to preserve three-state semantics for all fields
  • Option B: Apply ?? null consistently to all fields (including imageUrl) and document why date fields need different treatment

Apply this diff to make string field handling consistent with date fields:

     this.imageUrl = data.image_url;
-    this.userId = data.user_id ?? null;
-    this.email = data.email ?? null;
-    this.firstName = data.first_name ?? null;
-    this.lastName = data.last_name ?? null;
-    this.organizationId = data.organization_id ?? null;
-    this.organizationName = data.organization_name ?? null;
+    this.userId = data.user_id === undefined ? undefined : data.user_id;
+    this.email = data.email === undefined ? undefined : data.email;
+    this.firstName = data.first_name === undefined ? undefined : data.first_name;
+    this.lastName = data.last_name === undefined ? undefined : data.last_name;
+    this.organizationId = data.organization_id === undefined ? undefined : data.organization_id;
+    this.organizationName = data.organization_name === undefined ? undefined : data.organization_name;

Also applies to: 30-42

packages/shared/src/types/billing.ts (1)

134-140: This concern was already raised in a previous review.

The nullable type changes for annualFee and annualMonthlyFee were flagged previously, with specific consumer code locations identified that use non-null assertions (!) and will break type safety. Please refer to the existing review comment for details on the affected files and suggested solutions.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d68a042 and bf84fa6.

📒 Files selected for processing (11)
  • packages/clerk-js/src/core/constants.ts (1 hunks)
  • packages/clerk-js/src/core/resources/BillingCheckout.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingPayer.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingPayment.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingSubscription.ts (2 hunks)
  • packages/clerk-js/src/core/resources/CommerceSettings.ts (2 hunks)
  • packages/clerk-js/src/utils/billing.ts (1 hunks)
  • packages/shared/src/types/billing.ts (13 hunks)
  • packages/shared/src/types/commerceSettings.ts (2 hunks)
  • packages/shared/src/types/json.ts (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/clerk-js/src/core/constants.ts
  • packages/clerk-js/src/utils/billing.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/clerk-js/src/core/resources/BillingCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/shared/src/types/commerceSettings.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/clerk-js/src/core/resources/BillingCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/shared/src/types/commerceSettings.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/clerk-js/src/core/resources/BillingCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/shared/src/types/commerceSettings.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/clerk-js/src/core/resources/BillingCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/shared/src/types/commerceSettings.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/clerk-js/src/core/resources/BillingCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/shared/src/types/commerceSettings.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/clerk-js/src/core/resources/BillingCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
  • packages/clerk-js/src/core/resources/CommerceSettings.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/BillingPayment.ts
  • packages/clerk-js/src/core/resources/BillingPaymentMethod.ts
  • packages/shared/src/types/commerceSettings.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/json.ts
🧬 Code graph analysis (4)
packages/clerk-js/src/core/resources/BillingSubscription.ts (2)
packages/shared/src/types/billing.ts (2)
  • BillingMoneyAmount (629-646)
  • BillingSubscriptionItemResource (501-565)
packages/clerk-js/src/utils/billing.ts (1)
  • billingMoneyAmountFromJSON (10-17)
packages/clerk-js/src/core/resources/BillingPayment.ts (2)
packages/shared/src/types/billing.ts (1)
  • BillingPaymentMethodResource (275-344)
packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (1)
  • BillingPaymentMethod (17-79)
packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (1)
packages/shared/src/types/billing.ts (2)
  • BillingPaymentMethodResource (275-344)
  • BillingPaymentMethodStatus (222-222)
packages/shared/src/types/json.ts (1)
packages/shared/src/types/billing.ts (2)
  • BillingPayerResourceType (62-62)
  • BillingPaymentMethodStatus (222-222)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Build Packages
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (13)
packages/shared/src/types/commerceSettings.ts (1)

7-7: LGTM! Nullable Stripe key aligns with API version update.

The widening of stripe_publishable_key to allow null is appropriate for the 2025-10-01 API version. This aligns with the implementation in packages/clerk-js/src/core/resources/CommerceSettings.ts which now defaults to null instead of an empty string.

Also applies to: 21-21

packages/shared/src/types/json.ts (1)

622-629: LGTM! Extensive nullability updates align with API version 2025-10-01.

The changes appropriately widen types to support nullable/optional fields across billing entities. The pattern is generally consistent:

  • Optional-nullable (field?: Type | null) for fields that may be absent or explicitly null
  • Optional-only (field?: Type) for fields that are simply absent when not applicable (e.g., free_trial_ends_at)

This distinction appears intentional and aligns with the broader API surface changes across the PR.

Also applies to: 634-671, 707-718, 782-799, 804-840

packages/clerk-js/src/core/resources/BillingSubscription.ts (1)

26-29: Good use of optional pattern for conditional field.

The change from nextPayment: object | null to nextPayment?: object correctly uses undefined to indicate absence. The fromJSON logic only assigns when data.next_payment exists, leaving the field undefined otherwise. This is a cleaner pattern than explicit null assignment.

Note: This differs from other resources in this PR (e.g., BillingPayment) which use nullable with explicit null defaults. While both approaches are valid, consistency across the billing domain would improve maintainability.

Also applies to: 50-55

packages/clerk-js/src/core/resources/BillingCheckout.ts (1)

31-31: LGTM! Consistent optional pattern for conditional field.

The change from freeTrialEndsAt: Date | null to freeTrialEndsAt?: Date follows the same pattern as BillingSubscription.nextPayment, using undefined for absence. The conditional assignment in fromJSON correctly leaves the field undefined when not present.

Also applies to: 55-57

packages/clerk-js/src/core/resources/CommerceSettings.ts (1)

10-10: LGTM! Default change aligns with nullable type.

The default value change from '' (empty string) to null aligns with the type definition update in packages/shared/src/types/commerceSettings.ts. The direct assignment in fromJSON without fallbacks is appropriate given the null default initialization.

Also applies to: 31-35

packages/clerk-js/src/core/resources/BillingPaymentMethod.ts (1)

19-29: LGTM! Proper three-state handling for optional-nullable fields.

The new fields and type changes appropriately support the expanded API surface. The fromJSON date handling correctly preserves the distinction between undefined (field absent) and null (field present but null):

this.createdAt = data.created_at == null ? data.created_at : unixEpochToDate(data.created_at);

This pattern is consistent with the field declarations (createdAt?: Date | null) and maintains proper three-state semantics.

Also applies to: 36-55

packages/clerk-js/src/core/resources/BillingPayment.ts (1)

18-21: Inconsistency confirmed; standardization decision depends on API contract.

The null-handling pattern inconsistency is verified:

  • BillingPayment uses explicit Date | null = null defaults (required fields that can be null)
  • Other billing resources use ?: Type pattern (optional fields)
  • BillingPaymentMethod uses a hybrid ?: Date | null approach

The explicit null defaults in BillingPayment are semantically justified—the initialization code shows conditional assignment to null: this.paidAt = data.paid_at ? unixEpochToDate(data.paid_at) : null, confirming these fields legitimately can be null.

The inconsistency creates confusion. To resolve, determine the standard across billing resources:

  1. If all nullable fields should be explicit (Type | null = null), update other resources to match
  2. If all should be optional-or-nullable (?: Type | null), update BillingPayment to match
  3. Verify the API contract to ensure the chosen pattern reflects actual response behavior
packages/shared/src/types/billing.ts (6)

689-702: Good refactor to explicit interface definition.

Replacing the Omit-based structure with an explicit interface definition for BillingStatementTotals improves type clarity and maintainability.


720-754: The verification confirms that the paymentSourceIdpaymentMethodId rename has been fully completed across the codebase with no remaining references to the old parameter name. All consumer code and tests have been updated consistently.


283-323: Consumer code already handles optionality changes with defensive patterns.

Verification confirms all consumer code uses proper defensive patterns for the optional fields:

  • Nullish coalescing on paymentType, cardType, last4: paymentMethod.paymentType ?? 'card'
  • Boolean fields correctly handled as falsy when undefined: if (!paymentMethod.isDefault), {paymentMethod.isDefault && ...}
  • Sorting explicitly converts to boolean: a.isDefault ?? false
  • The 'link' payment type removal has zero impact (no usages in codebase)

No breaking changes detected in existing consumers.


395-407: No issues found — nullable field changes are properly handled by consumers.

Verification confirms that the nullable changes to paidAt, failedAt, and paymentMethod fields in BillingPaymentResource are safe:

  • paidAt and failedAt are consistently guarded with OR operators that fall back to the non-nullable updatedAt field in PaymentAttempts components.
  • No unsafe null dereferences were found for the paymentMethod field.
  • The BillingPayment class implementation already declares these fields as nullable with null defaults, ensuring consistency with the type definition.

669-681: Nullable field handling in BillingCheckoutTotals is already properly implemented.

Verification confirms all consumer code correctly handles the nullable credit and pastDue fields using optional chaining with short-circuit evaluation (CheckoutForm.tsx:57-58), and totalDueAfterFreeTrial is properly deserialized with null checks (billing.ts:40-42). No unsafe direct property accesses exist.


204-214: Consumer code properly handles nullable description and avatarUrl fields.

Verification confirms that:

  • Both Feature class implementations (clerk-js and backend) correctly initialize these fields as null and handle null coercion in their fromJSON() methods
  • The primary consumer in PlanDetails.tsx uses proper null-checks (feature.avatarUrl ? ( and feature.description ? () before rendering these fields
  • No unsafe direct property access patterns were found

The implementation is type-safe and correct.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/clerk-js/src/core/resources/Feature.ts (1)

24-26: Add null-coalescing to handle optional JSON fields.

The fields description and avatarUrl are typed as string | null, but FeatureJSON likely defines them as optional (description?: string | null). When these fields are missing from the JSON, data.description and data.avatar_url will be undefined, which doesn't match the field type. This creates a type inconsistency that can lead to runtime bugs if other code expects these fields to be string | null (never undefined).

Apply this diff to normalize undefined to null:

     this.id = data.id;
     this.name = data.name;
-    this.description = data.description;
+    this.description = data.description ?? null;
     this.slug = data.slug;
-    this.avatarUrl = data.avatar_url;
+    this.avatarUrl = data.avatar_url ?? null;
packages/clerk-js/src/core/resources/BillingPayer.ts (1)

24-44: Inconsistent null-to-undefined conversion between field types.

The fromJSON method handles null values differently across field types:

  1. Date fields (lines 30–35): Use if-guards that convert both null and undefined to undefined (field not assigned), matching their type signature createdAt?: Date which excludes null.
  2. String fields (lines 36–42): Use direct assignment that preserves null as null and undefined as undefined, creating three-state semantics.

This inconsistency makes the intent unclear. While date fields explicitly normalize nullundefined to match their types, string fields preserve whatever the API returns. This creates different null-handling semantics across the resource.

Consider standardizing the approach:

Option 1 (Recommended): Make string field handling explicit to match the intent of date fields:

-    this.imageUrl = data.image_url;
-    this.userId = data.user_id;
-    this.email = data.email;
-    this.firstName = data.first_name;
-    this.lastName = data.last_name;
-    this.organizationId = data.organization_id;
-    this.organizationName = data.organization_name;
+    this.imageUrl = data.image_url === undefined ? undefined : data.image_url;
+    this.userId = data.user_id ?? null;
+    this.email = data.email === undefined ? undefined : data.email ?? null;
+    this.firstName = data.first_name === undefined ? undefined : data.first_name ?? null;
+    this.lastName = data.last_name === undefined ? undefined : data.last_name ?? null;
+    this.organizationId = data.organization_id ?? null;
+    this.organizationName = data.organization_name === undefined ? undefined : data.organization_name ?? null;

This preserves undefined for optional fields while converting null appropriately for each field's type signature.

Option 2: Document the three-state semantics as intentional and ensure the API contract and downstream consumers handle all three states correctly.

Based on past review comments

🧹 Nitpick comments (3)
integration/tests/pricing-table.test.ts (1)

845-874: Well-designed test helpers with clear documentation.

The helper functions improve test readability and maintainability. The use of Clerk-specific CSS classes and XPath selectors is appropriate for integration tests, though it does couple the tests to the component's DOM structure.

Per the TypeScript coding guidelines, consider adding explicit return types and parameter types for better type safety and documentation:

-function matchLineItem(root: Locator, title: string | RegExp, description?: string | RegExp): Locator {
+function matchLineItem(root: Locator, title: string | RegExp, description?: string | RegExp): Locator {
   // Find the title element using the Clerk-generated class
   const titleElement = root.locator('.cl-lineItemsTitle').filter({ hasText: title });
 
   // If no description is provided, return the title element
   if (description === undefined) {
     return titleElement;
   }
 
   // Get the next sibling description element using the Clerk-generated class
   const descriptionElement = titleElement
     .locator('xpath=following-sibling::*[1][contains(@class, "cl-lineItemsDescription")]')
     .filter({ hasText: description });
 
   return descriptionElement;
 }
 
 /**
  * Helper to count the number of line items within a given root element.
  * Line items are rendered as Clerk LineItems components where each .cl-lineItemsTitle represents a line item.
  */
-async function countLineItems(root: Locator): Promise<number> {
+async function countLineItems(root: Locator): Promise<number> {
   return await root.locator('.cl-lineItemsTitle').count();
 }

Note: The return types are already present, but you may want to verify parameter types are correctly inferred throughout usage.

packages/testing/src/playwright/unstable/page-objects/statement.ts (1)

9-33: Consider consistent access to the root locator.

Methods access the root locator inconsistently—some use the root const directly (lines 10, 13, 20) while others use self.root (lines 23, 29, 32). While both approaches work, using self.root consistently would be clearer.

Example for lines 10, 13:

 waitForMounted: () => {
-  return root.waitFor({ state: 'visible', timeout: 15000 });
+  return self.root.waitFor({ state: 'visible', timeout: 15000 });
 },
 waitForUnmounted: () => {
-  return root.waitFor({ state: 'detached', timeout: 15000 });
+  return self.root.waitFor({ state: 'detached', timeout: 15000 });
 },
packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts (1)

9-31: Consider consistent access to the root locator.

Methods access the root locator inconsistently—some use the root const directly (lines 10, 13, 20) while others use self.root (lines 23, 26, 29). While both approaches work, using self.root consistently would be clearer.

Example for lines 10, 13:

 waitForMounted: () => {
-  return root.waitFor({ state: 'visible', timeout: 15000 });
+  return self.root.waitFor({ state: 'visible', timeout: 15000 });
 },
 waitForUnmounted: () => {
-  return root.waitFor({ state: 'detached', timeout: 15000 });
+  return self.root.waitFor({ state: 'detached', timeout: 15000 });
 },
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between bf84fa6 and 820be73.

📒 Files selected for processing (12)
  • integration/tests/pricing-table.test.ts (5 hunks)
  • packages/clerk-js/src/core/resources/BillingPayer.ts (2 hunks)
  • packages/clerk-js/src/core/resources/BillingPlan.ts (2 hunks)
  • packages/clerk-js/src/core/resources/Feature.ts (1 hunks)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx (2 hunks)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx (4 hunks)
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx (0 hunks)
  • packages/shared/src/react/hooks/useCheckout.ts (1 hunks)
  • packages/testing/src/playwright/unstable/page-objects/index.ts (2 hunks)
  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts (1 hunks)
  • packages/testing/src/playwright/unstable/page-objects/statement.ts (1 hunks)
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/clerk-js/src/ui/components/PaymentMethods/PaymentMethodRow.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/clerk-js/src/ui/components/Checkout/CheckoutComplete.tsx
  • packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
  • packages/clerk-js/src/core/resources/BillingPlan.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

**/*.{js,jsx,ts,tsx}: All code must pass ESLint checks with the project's configuration
Follow established naming conventions (PascalCase for components, camelCase for variables)
Maintain comprehensive JSDoc comments for public APIs
Use dynamic imports for optional features
All public APIs must be documented with JSDoc
Provide meaningful error messages to developers
Include error recovery suggestions where applicable
Log errors appropriately for debugging
Lazy load components and features when possible
Implement proper caching strategies
Use efficient data structures and algorithms
Profile and optimize critical paths
Validate all inputs and sanitize outputs
Implement proper logging with different levels

Files:

  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts
  • packages/testing/src/playwright/unstable/page-objects/statement.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • integration/tests/pricing-table.test.ts
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts
  • packages/testing/src/playwright/unstable/page-objects/index.ts
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
**/*.{js,jsx,ts,tsx,json,css,scss,md,yaml,yml}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use Prettier for consistent code formatting

Files:

  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts
  • packages/testing/src/playwright/unstable/page-objects/statement.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • integration/tests/pricing-table.test.ts
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts
  • packages/testing/src/playwright/unstable/page-objects/index.ts
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
packages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

TypeScript is required for all packages

Files:

  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts
  • packages/testing/src/playwright/unstable/page-objects/statement.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts
  • packages/testing/src/playwright/unstable/page-objects/index.ts
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
packages/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Packages should export TypeScript types alongside runtime code

Files:

  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts
  • packages/testing/src/playwright/unstable/page-objects/statement.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts
  • packages/testing/src/playwright/unstable/page-objects/index.ts
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use proper TypeScript error types

**/*.{ts,tsx}: Always define explicit return types for functions, especially public APIs
Use proper type annotations for variables and parameters where inference isn't clear
Avoid any type - prefer unknown when type is uncertain, then narrow with type guards
Use interface for object shapes that might be extended
Use type for unions, primitives, and computed types
Prefer readonly properties for immutable data structures
Use private for internal implementation details
Use protected for inheritance hierarchies
Use public explicitly for clarity in public APIs
Prefer readonly for properties that shouldn't change after construction
Prefer composition and interfaces over deep inheritance chains
Use mixins for shared behavior across unrelated classes
Implement dependency injection for loose coupling
Let TypeScript infer when types are obvious
Use const assertions for literal types: as const
Use satisfies operator for type checking without widening
Use mapped types for transforming object types
Use conditional types for type-level logic
Leverage template literal types for string manipulation
Use ES6 imports/exports consistently
Use default exports sparingly, prefer named exports
Use type-only imports: import type { ... } from ...
No any types without justification
Proper error handling with typed errors
Consistent use of readonly for immutable data
Proper generic constraints
No unused type parameters
Proper use of utility types instead of manual type construction
Type-only imports where possible
Proper tree-shaking friendly exports
No circular dependencies
Efficient type computations (avoid deep recursion)

Files:

  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts
  • packages/testing/src/playwright/unstable/page-objects/statement.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • integration/tests/pricing-table.test.ts
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts
  • packages/testing/src/playwright/unstable/page-objects/index.ts
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Support multiple Clerk environment variables (CLERK_, NEXT_PUBLIC_CLERK_, etc.) for configuration.

Files:

  • packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts
  • packages/testing/src/playwright/unstable/page-objects/statement.ts
  • packages/clerk-js/src/core/resources/Feature.ts
  • integration/tests/pricing-table.test.ts
  • packages/testing/src/playwright/unstable/page-objects/userProfile.ts
  • packages/testing/src/playwright/unstable/page-objects/index.ts
  • packages/shared/src/react/hooks/useCheckout.ts
  • packages/clerk-js/src/core/resources/BillingPayer.ts
integration/**

📄 CodeRabbit inference engine (.cursor/rules/global.mdc)

Framework integration templates and E2E tests should be placed under the integration/ directory

Files:

  • integration/tests/pricing-table.test.ts
integration/**/*

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

End-to-end tests and integration templates must be located in the 'integration/' directory.

Files:

  • integration/tests/pricing-table.test.ts
integration/**/*.{test,spec}.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/monorepo.mdc)

Integration tests should use Playwright.

Files:

  • integration/tests/pricing-table.test.ts
packages/**/index.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/development.mdc)

Use tree-shaking friendly exports

Files:

  • packages/testing/src/playwright/unstable/page-objects/index.ts
**/index.ts

📄 CodeRabbit inference engine (.cursor/rules/react.mdc)

Use index.ts files for clean imports but avoid deep barrel exports

Avoid barrel files (index.ts re-exports) as they can cause circular dependencies

Files:

  • packages/testing/src/playwright/unstable/page-objects/index.ts
🧬 Code graph analysis (2)
integration/tests/pricing-table.test.ts (1)
integration/testUtils/index.ts (1)
  • createTestUtils (24-86)
packages/testing/src/playwright/unstable/page-objects/index.ts (2)
packages/testing/src/playwright/unstable/page-objects/statement.ts (1)
  • createStatementPageObject (4-38)
packages/testing/src/playwright/unstable/page-objects/paymentAttempt.ts (1)
  • createPaymentAttemptPageObject (4-35)
🪛 ast-grep (0.39.7)
integration/tests/pricing-table.test.ts

[warning] 730-730: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(date, 'i')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Packages
  • GitHub Check: Formatting | Dedupe | Changeset
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: semgrep-cloud-platform/scan
  • GitHub Check: semgrep-cloud-platform/scan
🔇 Additional comments (7)
integration/tests/pricing-table.test.ts (4)

1-1: LGTM: Type-only import follows best practices.

Properly uses import type for the Locator type, which improves tree-shaking and aligns with TypeScript conventions.


282-296: LGTM: Refactored assertions improve test maintainability.

The use of matchLineItem and countLineItems helpers makes the test more readable and resilient to minor DOM changes. The regex patterns correctly match dynamic trial period text, and the exact count verification ensures no unexpected line items appear.


356-368: LGTM: Consistent use of helpers throughout the test.

The assertions correctly verify both the presence of expected line items and the absence of trial-related items after conversion to a paid subscription. The count verification adds valuable coverage.


673-775: Excellent test coverage for billing history flows.

This test comprehensively validates the billing history navigation, including statements, payment attempts, and UI state transitions. The test properly exercises both successful and failed payment scenarios and uses appropriate cleanup patterns.

The ReDoS concern flagged at line 730 is confirmed to be a false positive. The toLocaleDateString() produces a simple, predictable format (November 2025), resulting in a safe regex pattern that cannot be exploited for ReDoS attacks.

packages/clerk-js/src/core/resources/Feature.ts (1)

8-10: Verify null-coalescing in fromJSON for nullable fields.

The change to make description and avatarUrl nullable is appropriate for handling optional API fields. However, the fromJSON method (lines 24, 26) assigns these values directly without null-coalescing. If FeatureJSON defines these as optional (description?: string | null), then data.description could be undefined, but the field is typed as string | null (excluding undefined).

Ensure the fromJSON method uses null-coalescing to normalize undefined to null.

packages/shared/src/react/hooks/useCheckout.ts (1)

117-117: LGTM! The addition of planPeriodStart: null is correct and type-safe.

Verification confirms that planPeriodStart is present on BillingCheckoutResource and properly included in CheckoutProperties (which derives from BillingCheckoutResource minus only pathRoot and status). The null initialization follows the correct pattern, enforced by the satisfies ForceNull<CheckoutProperties> constraint at line 118, and the spread operator at line 126 will automatically include this property when checkout data is available.

packages/testing/src/playwright/unstable/page-objects/index.ts (1)

12-13: LGTM! New page objects properly integrated.

The new statement and paymentAttempt page objects are correctly imported and exported, following the established pattern in this file.

Also applies to: 47-48

@panteliselef panteliselef changed the title [WIP] feat(backend, clerk-js): Update the supported API version to 2025-10-01 feat(backend, clerk-js): Update the supported API version to 2025-11-10 Nov 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants